/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_kit/zhiqim_git.htm
 *
 * ZhiqimGit is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.git.objer.objectid;

import java.io.IOException;

import org.zhiqim.git.GitI18n;
import org.zhiqim.git.GitWalker;
import org.zhiqim.git.objer.ObjectLoader;

import org.zhiqim.kernel.util.Asserts;

/**
 * 修订过程中的对象基类
 *
 * @version v1.0.0 @author zouzhigang 2016-12-13 新建与整理
 */
public abstract class RevObject extends ObjectId
{
    //基础标志（是否解析&是否已存在）
    protected boolean parsed;
    protected boolean existed;
    
    //HTTP传输时使用的标志信息
    protected boolean want;
    protected boolean have;
    protected boolean written;

    public RevObject(ObjectId id)
    {
        super(id);
    }
    
    /***********************************************************************/
    //子类必须实现的方法
    /***********************************************************************/
    
    /**
     * 对象类型, @see OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, OBJ_TAG
     * 
     * @return              int类型
     */
    public abstract int getType();
    
    /**
     * 解析头部信息
     * 
     * @param walk          步行器
     * @throws IOException  IO异常
     */
    public abstract void parseHeaders(GitWalker walk) throws IOException;

    /**
     * 解析主体部分
     * 
     * @param walk          步行器
     * @throws IOException  IO异常
     */
    public abstract void parseBody(GitWalker walk) throws IOException;
    
    /**
     * 获取主体缓冲，返回缓冲字节数组
     * 
     * @return              字节数组
     */
    public abstract byte[] getContent();
    
    /**
     * 清除主体缓冲
     */
    public abstract void disposeContent();
    
    /***********************************************************************/
    //子类使用的加载和读取标志的方法
    /***********************************************************************/
    
    protected final byte[] loadCanonical(GitWalker walk) throws IOException
    {
        ObjectLoader ldr = walk.git().getObjectLoader(this);
        
        Asserts.assertNotNull(ldr, GitI18n.objectNotFound, this);
        Asserts.asserts(getType() == ldr.getType(), GitI18n.objectTypeMismatch, this, getType(), ldr.getType());
        
        return ldr.getData();
    }
    
    protected void appendFlags(StringBuilder strb)
    {
        strb.append(parsed?'p':'-');
        strb.append(existed?'e':'-');
        strb.append(want?'w':'-');
        strb.append(have?'h':'-');
    }

    /***********************************************************************/
    //标志设置方法
    /***********************************************************************/
    
    public final boolean isParsed()
    {
        return parsed;
    }
    
    public final void setParsed()
    {
        this.parsed = true;
    }
    
    public final void setExisted()
    {
        this.existed = true;
    }
    
    public final boolean isExisted()
    {
        return existed;
    }
    
    public void setWant()
    {
        this.want = true;
    }
    
    public boolean isWant()
    {
        return want;
    }
    
    public void setHave()
    {
        this.have = true;
    }
    
    public boolean isHave()
    {
        return have;
    }
    
    public void setWritten()
    {
        this.written = true;
    }
    
    public boolean isWriten()
    {
        return written;
    }
    
    /***********************************************************************/
    //其他方法
    /***********************************************************************/
    
    @Override
    public final boolean equals(Object o)
    {
        return this == o;
    }
    
    @Override
    public String toString()
    {
        final StringBuilder s = new StringBuilder();
        s.append(type(getType()));
        s.append(' ');
        s.append(getName());
        s.append(' ');
        appendFlags(s);
        return s.toString();
    }
    
    /***********************************************************************/
    //子类的类型方法等
    /***********************************************************************/
    
    /** 是否有换行符 */
    protected static boolean hasLF(final byte[] r, int begin, final int end)
    {
        while (begin < end)
            if (r[begin++] == '\n')
                return true;
        return false;
    }
    
    /**
     * 类型编号转为字符串
     * 
     * @param type  修订对象类型int型
     * @return      修订对象类型String型
     */
    public static String type(int type)
    {
        switch (type)
        {
        case OBJ_COMMIT:
            return TYPE_COMMIT;
        case OBJ_TREE:
            return TYPE_TREE;
        case OBJ_BLOB:
            return TYPE_BLOB;
        case OBJ_TAG:
            return TYPE_TAG;
        default:
            throw Asserts.exception(GitI18n.illegalObjectType, type);
        }
    }
    
    /**
     * 类型编号字符串转int型
     * 
     * @param type  修订对象类型String型
     * @return      修订对象类型int型
     */
    public static int type(String type)
    {
        if (TYPE_COMMIT.equals(type))
            return OBJ_COMMIT;
        else if (TYPE_TREE.equals(type))
            return OBJ_TREE;
        else if (TYPE_BLOB.equals(type))
            return OBJ_BLOB;
        else if (TYPE_TAG.equals(type))
            return OBJ_TAG;
        else
            throw Asserts.exception(GitI18n.illegalObjectType, type);
    }

    /**
     * 类型编号转为字节数组类型
     * 
     * @param type  修订对象类型int型
     * @return          修订对象类型字节数组型
     */
    public static byte[] typeBytes(int type)
    {
        switch (type)
        {
        case OBJ_COMMIT:
            return TYPE_COMMIT_BYTES;
        case OBJ_TREE:
            return TYPE_TREE_BYTES;
        case OBJ_BLOB:
            return TYPE_BLOB_BYTES;
        case OBJ_TAG:
            return TYPE_TAG_BYTES;
        default:
            throw Asserts.exception(GitI18n.illegalObjectType, type);
        }
    }
}
